package com.hbwxz.admin.service;

import com.hbwxz.admin.pojo.*;
import com.hbwxz.admin.processor.RedisCommonProcessor;
import com.hbwxz.admin.repo.CommodityBrandRepository;
import com.hbwxz.admin.repo.CommodityCategoryBrandRepository;
import com.hbwxz.admin.repo.CommodityCategoryRepository;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CommodityCategoryService {

    @Autowired
    private RedisCommonProcessor redisCommonProcessor;

    @Autowired
    private CommodityCategoryRepository commodityCategoryRepository;

    @Autowired
    private CommodityCategoryBrandRepository commodityCategoryBrandRepository;

    @Autowired
    private CommodityBrandRepository commodityBrandRepository;
    @Autowired
    private RedissonClient redissonClient;

    public CommodityCategoryComposite getCategoryList() {
        Object cacheCategory = redisCommonProcessor.get("items");
        if(cacheCategory != null) {
            return (CommodityCategoryComposite)cacheCategory;
        }
        RLock itemsLock = redissonClient.getLock("itemsLock");
        try {
                       itemsLock.lock(30, TimeUnit.SECONDS);
            List<CommodityCategory> categoryList = commodityCategoryRepository.findAll();
            CommodityCategoryComposite items = generateCategoryTree(categoryList);
            if(items == null) {
                throw new UnsupportedOperationException("Product item shoud not be empty in DB");
            }
            redisCommonProcessor.set("items", items);
            return items;
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }finally {
            itemsLock.unlock();
        }
    }

    private CommodityCategoryComposite generateCategoryTree(List<CommodityCategory> categoryList) {
        List<CommodityCategoryComposite> composites = new ArrayList<CommodityCategoryComposite>(categoryList.size());
        categoryList.forEach(dbItem -> composites.add(
           CommodityCategoryComposite.builder().
                   id(dbItem.getId()).
                   name(dbItem.getName()).
                   parentId(dbItem.getParentId()).
                   build()
        ));
        Map<Long, List<CommodityCategoryComposite>> groupListing = composites.stream().collect(Collectors.groupingBy(CommodityCategoryComposite::getParentId));
        composites.stream().forEach(composite -> {
            List<CommodityCategoryComposite> list = groupListing.get(composite.getId());
            composite.setChild(list==null?new ArrayList<>():list);
        });
        return composites.size() > 0 ? composites.get(0) : null;
    }

    @Transactional
    public void createCategory(CommodityCategory commodityCategory) {
        CommodityCategory category = commodityCategoryRepository.findByName(commodityCategory.getName());
        if(category != null) {
            throw new RuntimeException("category already exist");
        }
        Date date = new Date();
        commodityCategory.setCreateTime(date);
        commodityCategory.setUpdateTime(date);
        commodityCategoryRepository.save(commodityCategory);
        //清除redis缓存
        redisCommonProcessor.remove("category");
    }

    @Transactional
    public void deleteCategory(Long id) {
        commodityCategoryRepository.deleteById(id);
        commodityCategoryBrandRepository.deleteByCategoryId(id);
        redisCommonProcessor.remove("category");

    }

    @Transactional
    public void createBrandRelation(Long brandId, Long categoryId) {
        Optional<CommodityCategory> cc = commodityCategoryRepository.findById(categoryId);
        if(!cc.isPresent()) {
            throw new RuntimeException("category id not exist");
        }
        Optional<CommodityBrand> cb = commodityBrandRepository.findById(brandId);
        if(!cb.isPresent()){
            throw new RuntimeException("brandId is not exist");
        }
        CommodityCategoryBrand build = CommodityCategoryBrand.builder()
                .brandId(brandId)
                .categoryId(categoryId)
                .build();
        commodityCategoryBrandRepository.save(build);
    }

    public void deleteBrandRelation(Long brandId, Long categoryId) {
        CommodityCategoryBrandPK commodityCategoryBrandPK = CommodityCategoryBrandPK.builder()
                .brandId(brandId)
                .categoryId(categoryId).build();
        commodityCategoryBrandRepository.deleteById(commodityCategoryBrandPK);
    }
}
